package cn.mandifal.order.service.impl;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

import cn.mandifal.mapper.*;
import cn.mandifal.order.service.OrderService;
import cn.mandifal.pojo.*;
import cn.mandifal.utils.IdWorker;
import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;

import entity.PageResult;

/**
 * 服务实现层
 * @author Administrator
 *
 */
@Service
@Transactional
public class OrderServiceImpl implements OrderService {

	@Autowired
	private DpOrdersMapper dpOrdersMapper;
	@Autowired
	private DpOrderItemMapper  dpOrderItemMapper;
	@Autowired
	private DpPayLogsMapper dpPayLogsMapper;
	@Autowired
	private DpItemMapper dpItemMapper;
	@Autowired
	private DpSellerMapper dpSellerMapper;


	/**
	 * 根据用户名和订单状态查询全部订单，对应我的订单功能
	 * @param username 用户名
	 * @param status 支付订单状态
	 * @return 返回包含该用户的支付订单信息，商家订单信息，以及每个商家订单的订单详情信息的列表
	 */
	@Override
	public List<PayAndOrderCombine> findAllOrder(String username,String status) {
		//定义 PayAndOrderCombine 类型的集合
		List<PayAndOrderCombine> list=new ArrayList<>();
		//根据用户名查询该用户的所有支付日志
		DpPayLogsExample dpPayLogsExample=new DpPayLogsExample();
		DpPayLogsExample.Criteria criteria = dpPayLogsExample.createCriteria();
		criteria.andUserIdEqualTo(username);
		//按照时间排序，后创建的先显示
		dpPayLogsExample.setOrderByClause("create_time");
		if (! "".equals(status) && status != null ){
			criteria.andTradeStateEqualTo(status);
		}
		//超时的订单不查询
		criteria.andTradeStateNotEqualTo("8");
		//得到支付日志列表
		List<DpPayLogs> dpPayLogsList = dpPayLogsMapper.selectByExample(dpPayLogsExample);
		//得到某一支付订单的订单列表
		for (DpPayLogs dpPayLogs:dpPayLogsList) {
			//得到商家订单号列表
			String[] orderList = dpPayLogs.getOrderList().split(",");
			List<OrderAndDescCombine> orderAndDescCombineList=new ArrayList<>();
			for (String orderId:orderList) {
				System.out.println("1---------"+orderId);
				//根据每个商家订单号，得到订单实体
				DpOrders dpOrders = dpOrdersMapper.selectByPrimaryKey(orderId);
				//根据订单中的商家 id 字段得到商家名字并赋值给订单中的商家 id 字段
				DpSeller dpSeller = dpSellerMapper.selectByPrimaryKey(dpOrders.getSellerId());
				dpOrders.setSellerId(dpSeller.getNickName());
				System.out.println("2---------"+dpOrders.getOrderId());
				//根据订单号得到订单详情列表
				DpOrderItemExample dpOrderItemExample=new DpOrderItemExample();
				DpOrderItemExample.Criteria criteria1 = dpOrderItemExample.createCriteria();
				criteria1.andOrderIdEqualTo(orderId);
				//得到订单详情列表
				List<DpOrderItem> orderItemList = dpOrderItemMapper.selectByExample(dpOrderItemExample);
				//定义 orderAndDescCombine 组合实体类
				OrderAndDescCombine orderAndDescCombine=new OrderAndDescCombine();
				//添加订单详情列表字段
				orderAndDescCombine.setDpOrderItemList(orderItemList);
				//添加订单实体字段
				orderAndDescCombine.setDpOrders(dpOrders);
				System.out.println("3---------"+orderAndDescCombine.getDpOrders().getOrderId());
				//把组合实体类添加到 list 集合中
				orderAndDescCombineList.add(orderAndDescCombine);
			}
			PayAndOrderCombine payAndOrderCombine=new PayAndOrderCombine();
			//向 payAndOrderCombine 中添加 orderAndDescCombine 类型的列表字段
			payAndOrderCombine.setOrderAndDescCombineList(orderAndDescCombineList);
			//向 payAndOrderCombine 中添加 DpPayLogs 字段
			payAndOrderCombine.setDpPayLogs(dpPayLogs);
			//把 payAndOrderCombine 实体添加到列表中
			System.out.println(payAndOrderCombine.getOrderAndDescCombineList().get(0).getDpOrders().getOrderId());
			list.add(payAndOrderCombine);
		}
		return list;
	}


	/**
	 * 条件查询
	 * @param orderItem
	 * @param pageNum 当前页 码
	 * @param pageSize 每页记录数
	 * @return
	 */
	@Override
	public PageResult search(DpOrderItem orderItem, int pageNum, int pageSize) {
		PageHelper.startPage(pageNum, pageSize);
		DpOrderItemExample example=new DpOrderItemExample();
		DpOrderItemExample.Criteria criteria = example.createCriteria();
		if (orderItem != null){
			if (orderItem.getId()!=null && !"".equals(orderItem.getId())){
				criteria.andIdEqualTo(orderItem.getId());
			}
			if (orderItem.getStatus()!=null && !"".equals(orderItem.getStatus())){
				criteria.andStatusEqualTo(orderItem.getStatus());
			}
			//设置查询此商户下的订单详情
			criteria.andSellerIdEqualTo(orderItem.getSellerId());
		}
		Page<DpOrderItem> page= (Page<DpOrderItem>)dpOrderItemMapper.selectByExample(example);
		return new PageResult(page.getTotal(), page.getResult());
	}


	@Autowired
	private RedisTemplate redisTemplate;
	
	@Autowired
	private IdWorker idWorker;

	/**
	 * 增加订单
	 * @param order 订单实体
	 */
	@Override
	public void add(DpOrders order) {
		
		//1.通过用户 id从redis中提取购物车列表
		List<Cart> cartList= (List<Cart>) redisTemplate.boundHashOps("cartList").get(order.getUserId());
		//定义订单号列表
		List<String> orderList=new ArrayList<>();
		//定义支付总金额
		double totalMoney=0;
		//2.循环购物车列表添加订单，添加的订单按照商家 id 来区分，所以重新创建一个 DpOrders 对象，
		//把按照商家来分的订单存入 DpOrders 表中
		for(Cart  cart:cartList){
			 //前端传过来 order 对象用于传递一些信息，如当前用户等
			DpOrders tbOrder=new DpOrders();
			//通过雪花算法工具类，获取订单主键ID(订单号)
			long orderId = idWorker.nextId();
			//设置订单 id
			tbOrder.setOrderId(orderId+"");
			//设置支付类型
			tbOrder.setPaymentType(order.getPaymentType());
			//设置订单状态，默认为未付款
			tbOrder.setStatus("0");
			//下单时间
			tbOrder.setCreateTime(new Date());
			//更新时间
			tbOrder.setUpdateTime(new Date());
			//当前用户
			tbOrder.setUserId(order.getUserId());
			//收货人地址
			tbOrder.setReceiverAreaName(order.getReceiverAreaName());
			//收货人电话
			tbOrder.setReceiverMobile(order.getReceiverMobile());
			//收货人
			tbOrder.setReceiver(order.getReceiver());
			//订单来源
			tbOrder.setSourceType(order.getSourceType());
			//商家ID
			tbOrder.setSellerId(cart.getSellerId());
			//合计数
			double money=0;
			//循环购物车中购物明细，存入订单明细表中，订单明细表中存的值为商家的不同商品sku的订单信息，是对 DpOrders 表中每个字段的再细分
			//在前端传值时，有些字段已经带了值所以在设置一些没有值得字段就行
			for(DpOrderItem orderItem:cart.getOrderItemList()  ){
				//主键
				orderItem.setId(idWorker.nextId()+"");
				//订单编号
				orderItem.setOrderId(orderId+"");
				//商家ID，购物车中有，而订单对象中没有，所以从购物车中取
				orderItem.setSellerId(cart.getSellerId());
				//设置设置订单详情状态,默认为未支付
				orderItem.setStatus("0");
				orderItem.setCreateTime(new Date());
				orderItem.setUpdateTime(new Date());
				//存入订单明细表
				dpOrderItemMapper.insert(orderItem);
				//累加所有商品的价钱
				money+=orderItem.getTotalFee().doubleValue();
				//减去库存,在控制层已经判断了库存是否充足
				//根据订单详情 id 查询商品 sku，并减去购买量
				//得到商品 sku
				DpItem dpItem = dpItemMapper.selectByPrimaryKey(orderItem.getItemId());
				//原有库存减商品sku购买量
				dpItem.setNum(dpItem.getNum().intValue()-orderItem.getNum().intValue());
				//保存更改
				dpItemMapper.updateByPrimaryKey(dpItem);
			}
			//合计，支付给该商家多少钱
			tbOrder.setPayment(new BigDecimal(money));
			//得到支付总金额
			totalMoney+=money;
			//得到商家（子订单）订单号列表
			orderList.add(orderId+"");
			dpOrdersMapper.insert(tbOrder);
		}
		//添加支付日志,支付日志与订单是 1 对多关系，
		// 在订单插入 DpOrders 时按照商家id拆分成了多个子订单，子订单中又按照商品拆分成了多个订单明细
		//支付日志中记录的就是总的支付金额
		//支付类型为在线支付则添加支付日志表
		if ("1".equals(order.getPaymentType())){
			DpPayLogs dpPayLogs =new DpPayLogs();
			//支付订单号
			dpPayLogs.setOutTradeNo(idWorker.nextId()+"");
			//设置用户 id
			dpPayLogs.setUserId(order.getUserId());
			//支付订单号创建日期
			dpPayLogs.setCreateTime(new Date());
			//设置支付总金额,支付日志中存的总金额以元为单位
			dpPayLogs.setTotalFee((long) (totalMoney));
			//交易状态,0为未支付
			dpPayLogs.setTradeState("0");
			//设置支付类型
			dpPayLogs.setPayType("1");
			//添加商家（子订单）订单号列表,因为是 list 类型，所以转换成字符串后带[ ]，而存的时候是用逗号分开的订单号，所以去掉两个中括号
			//使用""代替[ 和 ]
			dpPayLogs.setOrderList(orderList.toString().replace("[","").replace("]","").replace(" ", ""));
			//插入支付日志表
			dpPayLogsMapper.insert(dpPayLogs);
			//将支付日志实体放入缓存，以便支付时调用,以pay-支付订单号为 key，支付日志实体为value
			String key="pay"+"-"+dpPayLogs.getOutTradeNo();
			//存入redis 的 key 相同，原来的 value 会被新的 value 覆盖
			redisTemplate.opsForValue().set(key,dpPayLogs,900L, TimeUnit.SECONDS);

		}
		//3.清除redis中的购物车
		redisTemplate.boundHashOps("cartList").delete(order.getUserId());
	}

	/**
	 * 在添加订单时检查商品 sku 的库存和状态
	 * @param userId 用户 id
	 * @return
	 */
	@Override
	public Boolean checkStockAndStatusAtAddOrder(String userId){
		//从缓存中得到购物车列表
		List<Cart> cartList = (List<Cart>) redisTemplate.boundHashOps("cartList").get(userId);
		//如果缓存中有此用户的购物车
		if (cartList !=null){
			//遍历购物车列表,得到每个商家的购物车
			for (Cart cart:cartList) {
				//遍历每个商家的购物车得到购物明细项
				for (DpOrderItem orderItem:cart.getOrderItemList()) {
					//得到商品 sku id
					Long itemId = orderItem.getItemId();
					//根据商品sku id 查询数据库，
					DpItem dpItem = dpItemMapper.selectByPrimaryKey(itemId);
					if (dpItem!=null){
						//判断是否上架
						if (! "1".equals(dpItem.getStatus())) {
							return false;
						}
						//判断商品库存是否小于购买数量
						if (dpItem.getNum().intValue() < orderItem.getNum().intValue()){
							return false;
						}
					}else {
						//等于空返回 false
						return false;
					}
				}
			}
		}else {
			//如果没有购物车列表则返回 false
			return false;
		}
		return true;
	}

	/**
	 * 修改
	 */
	@Override
	public void update(DpOrders order){
		dpOrdersMapper.updateByPrimaryKey(order);
	}	
	
	/**
	 * 根据ID获取实体
	 * @param id
	 * @return
	 */
	@Override
	public DpOrders findOne(String id){
		return dpOrdersMapper.selectByPrimaryKey(id);
	}

	/**
	 * 根据订单详情id，查询实体
	 * @param id
	 * @return
	 */
    @Override
    public DpOrderItem findOderItem(String id) {
		return dpOrderItemMapper.selectByPrimaryKey(id);
    }

	/**
	 * 通过订单 id 查询所有的订单详情
	 * @param id 订单 id
	 * @return
	 */
	@Override
	public List<DpOrderItem> findOderItemByOrderId(String id) {
		DpOrderItemExample dpOrderItemExample=new DpOrderItemExample();
		DpOrderItemExample.Criteria criteria = dpOrderItemExample.createCriteria();
		criteria.andOrderIdEqualTo(id);
		List<DpOrderItem> orderItemList = dpOrderItemMapper.selectByExample(dpOrderItemExample);
		return orderItemList;
	}

	/**
	 * 批量删除
	 */
	@Override
	public void delete(String[] ids) {
		for(String id:ids){
			dpOrdersMapper.deleteByPrimaryKey(id);
		}		
	}

	/**
	 * 根据pay-支付订单号的组合串从缓存中搜索用户的支付日志,缓存时间为 15 分钟
	 * @param userId 用户名
	 * @return
	 */
	@Override
	public DpPayLogs searchDpPayLogFromRedis(String userId) {
		return (DpPayLogs) redisTemplate.opsForValue().get(userId);
	}

	/**
	 * 修改订单状态为已支付，为支付表和订单详情表添加支付宝流水号字段并删除 redis 中的支付订单
	 * @param out_trade_no 支付日志表的支付订单号
	 * @param transaction_id 支付流水号
	 */
	@Override
	public void updateOrderStatus(String out_trade_no, String transaction_id,String status) {
		//0.根据支付订单号删除 redis 中的支付订单实体
		String key="pay"+"-"+out_trade_no;
		redisTemplate.delete(key);
		//1.根据支付订单号得到支付日志实体
		DpPayLogs dpPayLogs = dpPayLogsMapper.selectByPrimaryKey(out_trade_no);
		System.out.println(dpPayLogs);
		//设置为已支付状态
		dpPayLogs.setTradeState(status);
		//设置支付时间
		Date date=new Date();
		dpPayLogs.setPayTime(date);
		//设置支付宝流水号
		dpPayLogs.setTransactionId(transaction_id);
		//保存到数据库
		dpPayLogsMapper.updateByPrimaryKey(dpPayLogs);
		//2.修改订单表的订单状态
		//根据逗号截取，得到订单id列表
		String[] orderIdList = dpPayLogs.getOrderList().split(",");
		//遍历，设置每个订单的状态
		for (String orderId:orderIdList) {
			//根据 id 得到订单实体
			DpOrders dpOrders = dpOrdersMapper.selectByPrimaryKey(orderId);
			if (dpOrders!= null){
				dpOrders.setStatus(status);
				dpOrders.setPaymentTime(date);
			}
			//保存修改到数据库
			dpOrdersMapper.updateByPrimaryKey(dpOrders);
			//根据订单 id 得到订单详情，并修改其状态
			DpOrderItemExample example=new DpOrderItemExample();
			DpOrderItemExample.Criteria criteria = example.createCriteria();
			criteria.andOrderIdEqualTo(orderId);
			List<DpOrderItem> list = dpOrderItemMapper.selectByExample(example);
			if (list.size()>0){
				//遍历订单详情列表，修改其状态
				for (DpOrderItem dpOrderItem:list) {
					dpOrderItem.setStatus(status);
					//更新时间
					dpOrderItem.setUpdateTime(new Date());
					//设置支付宝流水号
					dpOrderItem.setTransactionId(transaction_id);
					//保存修改
					dpOrderItemMapper.updateByPrimaryKey(dpOrderItem);
				}
			}
		}
		//根据用户 id 清除缓存中支付订单实体
		redisTemplate.delete(dpPayLogs.getUserId());
	}

	/**
	 * 修改订单详情表的状态，支付订单表和订单表的状态只有未支付与已支付，没有别的状态。
	 * @param orderItemId 订单详情 id
	 * @param status 目标状态
	 */
	@Override
	public void updateStatus( String orderItemId,String status) {
		//根据订单详情 id 得到订单详情实体
		DpOrderItem dpOrderItem = dpOrderItemMapper.selectByPrimaryKey(orderItemId);
		//设置状态
		dpOrderItem.setStatus(status);
		//保存
		dpOrderItemMapper.updateByPrimaryKey(dpOrderItem);
	}

	/**
	 * 返还库存
	 * @param orderItemId 订单详情 id
	 */
    @Override
    public void returnRepertory(String orderItemId) {
        //1.根据订单详情查询商品sku数量和 id
		DpOrderItem dpOrderItem = dpOrderItemMapper.selectByPrimaryKey(orderItemId);
		Integer num = dpOrderItem.getNum();
		Long itemId = dpOrderItem.getItemId();
		//查询商品 sku
		DpItem dpItem = dpItemMapper.selectByPrimaryKey(itemId);
		//设置数量,不使用 intvalue 转换 integer 对象为 int 数据类型也行，会自动装箱
		dpItem.setNum(dpItem.getNum().intValue()+num.intValue());
		//保存
		dpItemMapper.updateByPrimaryKey(dpItem);
	}

}
